package liquidfs.data.ops;

import java.io.*;

import liquidfs.*;
import liquidfs.core.*;
import liquidfs.data.*;
import liquidfs.data.ex.*;
import liquidfs.data.ops.WriteFileOperation.*;

public class SetFileLengthOperation extends AbstractFileModificationOperation {
   
   private long length;
   
	public SetFileLengthOperation(Revision current, Revision previous, String filepath, long length) {
		super(current, previous, filepath);
		this.length = length;
	}

	@Override
	public void fix (Application app, Object state, byte[] data) {
	   this.execute (app, null, null);
	}
	
	@Override
	public Void execute(Application app, InputStream in, OutputStream out) {
	   
	   // Get a reference to the file system
		LiquidFileSystem fs = app.getFileSystem();
		
		// If the file is local, write it
      if (fs.isLocal(this.getFilePath())) {
         File file = fs.getLocalFile(this.getFilePath());         
         RandomAccessFile disk;
         
         try {
            disk = new RandomAccessFile(file, "rws");
         }
         catch (java.io.FileNotFoundException e) {
            throw new liquidfs.data.ex.FileNotFoundException("Unable to find the file " + this.getFilePath() + ": " + e.getLocalizedMessage());
         }
         
         // Update the journal
         app.getJournal().startEntry(this, 0);
         
         try {          
            // Write this to the file
            disk.setLength(this.length);
         }
         catch (IOException e) {
            throw new FileSystemException("Unable to set the length of file " + this.getFilePath() + ": " + e.getLocalizedMessage());
         }
         finally {
            try {
               disk.close();
            }
            catch (IOException e) {
               throw new FileSystemException("Unable to properly close file " + this.getFilePath() + "; data may not have been written.");
            }
         }
         
         // Update the file's metadata
         Metadata metadata = fs.getMetadata(this.getFilePath());
         metadata.setModificationDate(this.getModificationDate());
         metadata.setLastAccessedDate(this.getModificationDate());
         metadata.setRevision(this.getCurrentRevision());
         fs.setMetadata(this.getFilePath(), metadata);
      }
		
      // Update the journal
      app.getJournal().startEntry(this, 1);
      
		// If it isn't local, iterate through each device we're connected two, except the ones that have already been queried
      for (Link link : app.getConfiguration().getLinks()) {
         
         // Skip devices that have already been queried
         if (this.reached(link.getDevice())) {
            continue;
         }
         
         // Pass this message along to other links in the network
         Result<Void> result = fs.relay(link, this, null, null);
         
         try {
            // Check for exceptions
            result.getData();
            continue;
         }
         catch (IgnoredException e) {
            continue;   // That's fine, keep going.
         }
         catch (ConflictException e) {
            app.getProblemBox().addProblem(this, e);
            continue;
         }
         catch (FileSystemException e) {
            app.getProblemBox().addProblem(this, e);
            continue;
         }
      }
      
      // Close the journal entry
      app.getJournal().endEntry();
      
      return null;
	}
}
